/*
 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#include "los_typedef.h"
#include "los_seq_buf.h"
#include "los_list.h"
#include "los_bitmap.h"
#include "los_devicelimit_pri.h"
#include "los_generallimit_pri.h"

#define TYPE_CHAR_LEN            (1)
#define DEVICE_NAME_PREFIX_SPACE (1)
#define DEVICE_ACCESS_MAXLEN     (3)
#define BUF_SEPARATOR            (5)

ProcDevLimiter g_procDevLimiter;

static inline struct ProcDirEntry *GetCurrDirectory(struct ProcDirEntry *dirEntry)
{
    return ((dirEntry == NULL) || S_ISDIR(dirEntry->mode)) ? dirEntry : dirEntry->parent;
}

static inline int IsSpace(int c)
{
	return (c == ' ' || (unsigned)c - '\t' < BUF_SEPARATOR);
}

static void DevAccessItemInit(DevAccessItem *devAccessItem)
{
    devAccessItem->access = 0;
    (VOID)memset_s(devAccessItem->name, PATH_MAX, 0, PATH_MAX);
    devAccessItem->type = 0;
    LOS_ListInit(&(devAccessItem->list));
    return ;
}

static bool DevLimitMatchItem(ListHead *list, DevAccessItem *item)
{
    if ((list == NULL) || (item == NULL)) {
        return false;
    }
    if (LOS_ListEmpty(list)) {
        return false;
    }
    DevAccessItem *walk = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY(walk, list, DevAccessItem, list) {
        if (item->type != walk->type) {
            continue;
        }
        if ((strcmp(walk->name, "*") != 0) && (strcmp(walk->name, item->name) != 0)) {
            continue;
        }
        if (!(item->access & ~(walk->access))) {
            return true;
        }
    }
    return false;
}

static bool DevLimitMatchItemPartial(ListHead *list, DevAccessItem *item)
{
    if ((list == NULL) || (item == NULL)) {
        return false;
    }
    if (LOS_ListEmpty(list)) {
        return false;
    }
    DevAccessItem *walk = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY(walk, list, DevAccessItem, list) {
        if (item->type != walk->type) {
            continue;
        }
        if ((strcmp(walk->name, "*") != 0) && (strcmp(item->name, "*") != 0)
        && (strcmp(walk->name, item->name) != 0)) {
            continue;
        }
        if (!(item->access & ~(walk->access))) {
            return true;
        }
    }
    return false;
}

static void DevAccessListDelete(ProcDevLimiter *devLimiter)
{
    if (devLimiter == NULL) {
        return;
    }
    DevAccessItem *delItem = NULL;
    DevAccessItem *tmpItem = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(delItem, tmpItem, &(devLimiter->accessList), DevAccessItem, list) {
        LOS_ListDelete(&(delItem->list));
        LOS_KernelFree((VOID *)delItem);
    }
}
static void DevLimiterCopyAccess(ProcDevLimiter *DevLimiterDest, ProcDevLimiter *DevLimiterSrc)
{
    if ((DevLimiterSrc == NULL) || (DevLimiterDest == NULL)) {
        return;
    }

    DevAccessItem *newItem = NULL;
    DevAccessItem *tmpItem = NULL;
    int itemSize = sizeof(DevAccessItem);
    DevLimiterDest->behavior = DevLimiterSrc->behavior;
    LOS_DL_LIST_FOR_EACH_ENTRY(tmpItem, &(DevLimiterSrc->accessList), DevAccessItem, list) {
        newItem = (DevAccessItem *)LOS_KernelMalloc(itemSize);
        if (newItem == NULL) {
            continue;
        }
        DevAccessItemInit(newItem);
        memcpy(newItem, tmpItem, itemSize);
        LOS_ListTailInsert(&(DevLimiterDest->accessList), &(newItem->list));
    }
}

static bool DevLimitHasChildren(ProcLimiterSet *procLimiterSet)
{
    if (procLimiterSet == NULL) {
        return false;
    }
    ProcLimiterSet *parent = procLimiterSet;
    bool ret = false;
    ProcDevLimiter *devLimiterRoot = (ProcDevLimiter *)(procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
    ProcLimiterSet *childProcLimiterSet = NULL;
    if (devLimiterRoot == NULL) {
        return ret;
    }
    LOS_DL_LIST_FOR_EACH_ENTRY(childProcLimiterSet, &(procLimiterSet->childList), ProcLimiterSet, childList) {
        if (childProcLimiterSet == NULL) {
            continue;
        }
        if (childProcLimiterSet->parent != parent) {
            continue;
        }
        if (!((childProcLimiterSet->mask) & BIT(PROCESS_LIMITER_ID_DEV))) {
            continue;
        }
        return true;
    }
    return ret;
}

static bool DevLimitMayAllowAll(ProcDevLimiter *parent)
{
    if (parent == NULL) {
        return true;
    }
    return (parent->behavior == DEVLIMIT_DEFAULT_ALLOW);
}

static bool DevLimitParentAllowsRmItem(ProcLimiter *parent, DevAccessItem *item)
{
    if (parent == NULL) {
        return true;
    }

    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(parent->private);
    if (devLimiter == NULL) {
        return true;
    }
     /* Make sure you're not removing part or a whole item existing in the parent plimits */
    return !DevLimitMatchItemPartial(&(devLimiter->accessList), item);
}

/**
 * This is used to make sure a child plimits won't have more privileges than its parent
 */
static bool DevLimitVerifyNewItem(ProcDevLimiter *parent, DevAccessItem *item, int currBehavior)
{
    if (parent == NULL) {
        return true;
    }
    if (parent->behavior == DEVLIMIT_DEFAULT_ALLOW) {
        if (currBehavior == DEVLIMIT_DEFAULT_ALLOW) {
            return true;
        }
        return !DevLimitMatchItemPartial(&(parent->accessList), item);
    }
    return DevLimitMatchItem(&(parent->accessList), item);
}

static bool DevLimitParentAllowsAddItem(ProcLimiter *parent, DevAccessItem *item, int currBehavior)
{
    if (parent == NULL) {
        return true;
    }
    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(parent->private);
    return DevLimitVerifyNewItem(devLimiter, item, currBehavior);
}

static void DevLimitAccessListRm(ProcDevLimiter *devLimiter, DevAccessItem *item)
{
    if ((item == NULL) || (devLimiter == NULL)) {
        return;
    }
    DevAccessItem *walk, *tmp = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(walk, tmp, &(devLimiter->accessList), DevAccessItem, list) {
        if (walk->type != item->type) {
            continue;
        }
        if (strcmp(walk->name, item->name) != 0) {
            continue;
        }
        walk->access &= ~item->access;
        if (!walk->access) {
            LOS_ListDelete(&walk->list);
            LOS_KernelFree((VOID *)walk);
        }
    }
}

static int DevLimitAccessListAdd(ProcDevLimiter *devLimiter, DevAccessItem *item)
{
    if ((item == NULL) || (devLimiter == NULL)) {
        return -ENOMEM;
    }

    DevAccessItem *walk = NULL;
    DevAccessItem *newItem = (DevAccessItem *)LOS_KernelMalloc(sizeof(DevAccessItem));
    if (newItem == NULL) {
        return -ENOMEM;
    }
    DevAccessItemInit(newItem);
    memcpy(newItem, item, sizeof(DevAccessItem));
    LOS_DL_LIST_FOR_EACH_ENTRY(walk, &(devLimiter->accessList), DevAccessItem, list){
        if (walk->type != item->type) {
            continue;
        }
        if (strcmp(walk->name, item->name) != 0) {
            continue;
        }
        walk->access |= item->access;
        LOS_KernelFree((VOID *)newItem);
        newItem = NULL;
    }

    if (newItem != NULL) {
        LOS_ListTailInsert(&(devLimiter->accessList), &(newItem->list));
    }
    return LOS_OK;
}

/**
 * Revalidate permissions
 */
static void DevLimitRevalidateActiveItems(ProcDevLimiter *devLimiter, ProcLimiter *parent)
{
    if ((devLimiter == NULL) || (parent == NULL)) {
        return;
    }
    DevAccessItem *walK = NULL;
    DevAccessItem *tmp = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(walK, tmp, &(devLimiter->accessList), DevAccessItem, list) {
        if (!DevLimitParentAllowsAddItem(parent, walK, devLimiter->behavior)) {
            DevLimitAccessListRm(devLimiter, walK);
        }
    }
}

/**
 * propagates a new item to the children
 */
static int DevLimitPropagateItem(ProcLimiterSet *procLimiterSet, DevAccessItem *item)
{
    if ((procLimiterSet == NULL) || (item == NULL)) {
        return -ENOMEM;
    }

    ProcLimiterSet *parent = procLimiterSet;
    INT32 ret = 0;
    ProcDevLimiter *devLimiterRoot = (ProcDevLimiter *)(procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
    ProcLimiterSet *childProcLimiterSet = NULL;
    if (devLimiterRoot == NULL) {
        return ret;
    }
    LOS_DL_LIST_FOR_EACH_ENTRY(childProcLimiterSet, &(procLimiterSet->childList), ProcLimiterSet, childList) {
        if (childProcLimiterSet == NULL) {
            continue;
        }
        if (childProcLimiterSet->parent != parent) {
            continue;
        }
        if (!((childProcLimiterSet->mask) & BIT(PROCESS_LIMITER_ID_DEV))) {
            continue;
        }
        ProcDevLimiter *devLimiterChild = (ProcDevLimiter *)(childProcLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
        if (devLimiterRoot->behavior == DEVLIMIT_DEFAULT_ALLOW &&
            devLimiterChild->behavior == DEVLIMIT_DEFAULT_ALLOW) {
            ret = DevLimitAccessListAdd(devLimiterChild, item);
        } else {
            DevLimitAccessListRm(devLimiterChild, item);
        }
        DevLimitRevalidateActiveItems(devLimiterChild, parent->procLimiterList[PROCESS_LIMITER_ID_DEV]);
    }
    return ret;
}

static ProcLimiter *GetProcLimiterFromProcDirEntry(struct ProcDirEntry *pde)
{
    if (pde == NULL) {
        return NULL;
    }
    ProcLimiterSet *procLimiterSet = pde->data;
    if (procLimiterSet == NULL) {
        return NULL;
    }
    ProcLimiter *procLimiter = procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV];
    return procLimiter;
}

static ProcLimiterSet *GetProcLimiterSetFromProcFile(struct ProcFile *pf)
{
    if (pf == NULL) {
        return NULL;
    }
    struct ProcDirEntry *pde = GetCurrDirectory(pf->pPDE);
    if (pde == NULL) {
        return NULL;
    }
    return (ProcLimiterSet *)pde->data;
}

static int ParseItemAccess(const char *buf, DevAccessItem *item)
{
    switch (*buf) {
        case 'a':
            item->type = DEVLIMIT_DEV_ALL;
            return LOS_OK;
        case 'b':
            item->type = DEVLIMIT_DEV_BLOCK;
            break;
        case 'c':
            item->type = DEVLIMIT_DEV_CHAR;
            break;
        default:
            return -EINVAL;
    }
    buf += DEVICE_NAME_PREFIX_SPACE;
    if (!IsSpace(*buf)) {
        return -EINVAL;
    }
    buf += DEVICE_NAME_PREFIX_SPACE;

    INT32 count = 0;
    for (count = 0; count < sizeof(item->name) - 1; count++) {
        if (IsSpace(*buf)) {
            break;
        }
        item->name[count] = *buf;
        buf += TYPE_CHAR_LEN;
    }
    if (!IsSpace(*buf)) {
        return -EINVAL;
    }

    buf += DEVICE_NAME_PREFIX_SPACE;
    for (count = 0; count < DEVICE_ACCESS_MAXLEN; count++) {
        switch (*buf) {
            case 'r':
                item->access |= DEVLIMIT_ACC_READ;
                break;
            case 'w':
                item->access |= DEVLIMIT_ACC_WRITE;
                break;
            case 'm':
                item->access |= DEVLIMIT_ACC_MKNOD;
                break;
            case '\n':
            case '\0':
                count = DEVICE_ACCESS_MAXLEN;
                break;
            default:
                return -EINVAL;
        }
        buf += TYPE_CHAR_LEN;
    }
    return LOS_OK;
}

static int DealItemAllAccess(ProcLimiterSet *procLimiterSet, int filetype)
{
    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
    ProcLimiter *parentProcLimiter = procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->parent;
    if (parentProcLimiter == NULL) {
        return -ENOMEM;
    }
    ProcDevLimiter *parent = (ProcDevLimiter *)(parentProcLimiter->private);
    if (parent == NULL) {
        return -ENOMEM;
    }

    switch (filetype) {
        case DEVLIMIT_ALLOW: {
            if (DevLimitHasChildren(procLimiterSet)) {
                return -EINVAL;
            }
            if (!DevLimitMayAllowAll(parent)) {
                return -EPERM;
            }
            DevAccessListDelete(devLimiter);
            devLimiter->behavior = DEVLIMIT_DEFAULT_ALLOW;
            if (!parent) {
                break;
            }
            DevLimiterCopyAccess(devLimiter, parent);
            break;
        }
        case DEVLIMIT_DENY: {
            if (DevLimitHasChildren(procLimiterSet)) {
                return -EINVAL;
            }
            DevAccessListDelete(devLimiter);
            devLimiter->behavior = DEVLIMIT_DEFAULT_DENY;
            break;
        }
        default:
            return -EINVAL;
    }
    return LOS_OK;
}

static int DevLimitUpdateAccess(ProcLimiterSet *procLimiterSet, int filetype, const char *buf)
{
    if ((buf == NULL) || (procLimiterSet == NULL)) {
        return -ENOMEM;
    }
    INT32 ret = 0;
    DevAccessItem item;
    DevAccessItemInit(&item);
    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
    ProcLimiter *parentProcLimiter = procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->parent;
    if (parentProcLimiter == NULL) {
        return -ENOMEM;
    }

    ret = ParseItemAccess(buf, &item);
    if (ret != LOS_OK) {
        return ret;
    }
    if (item.type == DEVLIMIT_DEV_ALL) {
        ret = DealItemAllAccess(procLimiterSet, filetype);
        return ret;
    }
    switch (filetype) {
        case DEVLIMIT_ALLOW: {
            if (devLimiter->behavior == DEVLIMIT_DEFAULT_ALLOW) {
                if (!DevLimitParentAllowsRmItem(parentProcLimiter, &item)) {
                    return -EPERM;
                }
                DevLimitAccessListRm(devLimiter, &item);
                break;
            }
            if (!DevLimitParentAllowsAddItem(parentProcLimiter, &item, devLimiter->behavior)) {
                return -EPERM;
            }
            ret = DevLimitAccessListAdd(devLimiter, &item);
            break;
        }
        case DEVLIMIT_DENY: {
            if (devLimiter->behavior == DEVLIMIT_DEFAULT_DENY) {
                DevLimitAccessListRm(devLimiter, &item);
            } else {
                ret = DevLimitAccessListAdd(devLimiter, &item);
            }
            //update child access list
            ret = DevLimitPropagateItem(procLimiterSet, &item);
            break;
        }
        default:
            ret = -EINVAL;
            break;
    }
    return ret;
}

static ssize_t ProcDevLimiterWrite(struct ProcFile *pf, const char *buf, int filetype)
{
    if (pf == NULL) {
        return -LOS_NOK;
    }

    ProcLimiterSet *procLimiterSet = GetProcLimiterSetFromProcFile(pf);
    if (procLimiterSet == NULL) {
        return -LOS_NOK;
    }
    INT32 retval = DevLimitUpdateAccess(procLimiterSet, filetype, buf);
    return retval;
}

static void DevLimitItemSetAccess(char *acc, short access)
{
    INT32 index = 0;
    (VOID)memset_s(acc, ACCLEN, 0, ACCLEN);
    if (access & DEVLIMIT_ACC_READ) {
        acc[index++] = 'r';
    }
    if (access & DEVLIMIT_ACC_WRITE) {
        acc[index++] = 'w';
    }
    if (access & DEVLIMIT_ACC_MKNOD) {
        acc[index++] = 'm';
    }
}

static char DevLimitItemTypeToChar(short type)
{
    if (type == DEVLIMIT_DEV_ALL) {
        return 'a';
    } else if (type == DEVLIMIT_DEV_CHAR) {
        return 'c';
    } else if (type == DEVLIMIT_DEV_BLOCK) {
        return 'b';
    }
    return 'X';
}

static inline short ConversionDevType(int vnodeType)
{
    INT16 type = 0;
    if (vnodeType == VNODE_TYPE_BLK) {
        type = DEVLIMIT_DEV_BLOCK;
    } else if (vnodeType == VNODE_TYPE_CHR) {
        type = DEVLIMIT_DEV_CHAR;
    }
    return type;
}

static inline short ConversionDevAccess(int flags)
{
    short access = 0;
    if ((flags & O_ACCMODE) == O_RDONLY) {
        access |= DEVLIMIT_ACC_READ;
    }
    if (flags & O_WRONLY) {
        access |= DEVLIMIT_ACC_WRITE;
    }
    if (flags & O_RDWR) {
        access |= DEVLIMIT_ACC_WRITE | DEVLIMIT_ACC_READ;
    }
    if (flags & O_CREAT) {
        access |= DEVLIMIT_ACC_MKNOD;
    }
    return access;
}

void DevLimiterInit(void)
{
    g_procDevLimiter.behavior = DEVLIMIT_DEFAULT_ALLOW;
    LOS_ListInit(&(g_procDevLimiter.accessList));
}

void* DevLimiterAlloc(void)
{
    ProcDevLimiter *plimiter = (ProcDevLimiter *)LOS_KernelMalloc(sizeof(ProcDevLimiter));
    if (plimiter == NULL) {
        return NULL;
    }
    plimiter->denyFile = 0;
    plimiter->allowFile = 0;
    plimiter->behavior = 0;
    LOS_ListInit(&(plimiter->accessList));
    plimiter->behavior = DEVLIMIT_DEFAULT_NONE;
    return (void *)plimiter;
}

void DevLimiterCopy(UINT8 *dest, UINT8 *src)
{
    if ((src == NULL) || (dest == NULL)) {
        return;
    }
    ProcDevLimiter *DevLimiterDest = (ProcDevLimiter *)dest;
    ProcDevLimiter *DevLimiterSrc = (ProcDevLimiter *)src;
    DevLimiterCopyAccess(DevLimiterDest, DevLimiterSrc);
}

void DevLimiterFree(struct ProcDirEntry *devPde)
{
    ProcLimiter *procLimiter = GetProcLimiterFromProcDirEntry(devPde);
    if (procLimiter == NULL) {
        return;
    }
    ProcDevLimiter *devLimite = (ProcDevLimiter *)procLimiter->private;
    DevAccessListDelete(devLimite);
    LOS_KernelFree((VOID *)devLimite);
    devLimite = NULL;
}

ssize_t ProcDevLimiterWriteAllow(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos)
{
    if (ProcDevLimiterWrite(pf, buf, DEVLIMIT_ALLOW) == LOS_OK) {
        return count;
    }
    return -LOS_NOK;
}

ssize_t ProcDevLimiterWriteDeny(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos)
{
    if (ProcDevLimiterWrite(pf, buf, DEVLIMIT_DENY) == LOS_OK) {
        return count;
    }
    return -LOS_NOK;
}

ssize_t ProcDevLimiterShow(struct SeqBuf *m, void *v)
{
    if ((m == NULL) || (v == NULL)) {
        return -LOS_NOK;
    }

    ProcLimiterSet *procLimiterSet = (ProcLimiterSet *)v;
    ProcLimiter *procLimiter = procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV];
    if (procLimiter == NULL) {
        return -LOS_NOK;
    }
    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(procLimiter->private);
    if (devLimiter == NULL) {
        return -LOS_NOK;
    }
    DevAccessItem *item = NULL;
    char acc[ACCLEN];

    if (devLimiter->behavior == DEVLIMIT_DEFAULT_ALLOW) {
        DevLimitItemSetAccess(acc, DEVLIMIT_ACC_MASK);
        LosBufPrintf(m, "%c %s %s\n", DevLimitItemTypeToChar(DEVLIMIT_DEV_ALL), "*", acc);
    } else {
        LOS_DL_LIST_FOR_EACH_ENTRY(item, &(devLimiter->accessList), DevAccessItem, list){
            DevLimitItemSetAccess(acc, item->access);
            LosBufPrintf(m, "%c %s %s\n", DevLimitItemTypeToChar(item->type), item->name, acc);
        }
    }
    return LOS_OK;
}

int DevLimitCheckPermission(int vnodeType, char *pathName, int flags)
{
    if (g_isInitProcLimiterSet == FALSE) {
        return LOS_OK;
    }
    LosTaskCB *runTask = OsCurrTaskGet();
    ProcLimiterSet *procLimiterSet = GetCurrProcLimiterSet(runTask);
    ProcLimiter *procLimiter = procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV];
    if (procLimiter == NULL) {
        return LOS_OK;
    }
    ProcDevLimiter *devLimiter = (ProcDevLimiter *)(procLimiterSet->procLimiterList[PROCESS_LIMITER_ID_DEV]->private);
    if (devLimiter == NULL) {
        return LOS_OK;
    }

    short type = ConversionDevType(vnodeType);
    short access = ConversionDevAccess(flags);
    DevAccessItem item;
    item.type = type;
    item.access = access;
    LOS_ListInit(&(item.list));
    (VOID)memset_s(item.name, PATH_MAX, 0, PATH_MAX);
    strncpy(item.name, pathName, strlen(pathName));

    BOOL matched = false;
    if (devLimiter->behavior == DEVLIMIT_DEFAULT_ALLOW) {
        matched = !DevLimitMatchItemPartial(&(devLimiter->accessList), &item);
    } else {
        matched = DevLimitMatchItem(&(devLimiter->accessList), &item);
    }
    if (!matched) {
        return -EPERM;
    }
    return LOS_OK;
}

